package com.reebake.ideal.security.code;

import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.BooleanUtil;
import com.reebake.ideal.security.authentication.AbstractAuthenticationProvider;
import com.reebake.ideal.security.entity.CodeCredential;
import com.reebake.ideal.security.entity.UserDetailsEntity;
import com.reebake.ideal.security.handler.UserDetailsServiceImpl;
import com.reebake.ideal.security.service.UserSecurityService;
import com.reebake.ideal.security.util.AuthenticationExceptionUtil;
import com.reebake.ideal.verify.code.core.VerifyCodeService;
import com.reebake.ideal.verify.code.entity.VerifyCodeEntity;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;

@RequiredArgsConstructor
@Slf4j
public class CodeAuthenticationProvider extends AbstractAuthenticationProvider {
    private final UserSecurityService userSecurityService;
    private final VerifyCodeService verifyCodeService;

    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        CodeAuthenticationToken authenticationToken = (CodeAuthenticationToken) authentication;
        CodeCredential codeCredential = (CodeCredential) authenticationToken.getCredentials();
        String username = codeCredential.getReceiver();
        String verifyCode = codeCredential.getVerifyCode();
        Boolean allowRegister = codeCredential.getAllowRegister();
        UserDetailsEntity userDetailsEntity = null;

        Boolean verifyCodeResult = verifyCodeService.check(username, verifyCode);
        if (BooleanUtil.isFalse(verifyCodeResult)) {
            log.debug("code verify failure");
            throw AuthenticationExceptionUtil.throwBadCredential();
        }
        if (Validator.isMobile(username)) {
            userDetailsEntity = userSecurityService.loadUserByPhoneNumber(username);
        }
        if (Validator.isEmail(username)) {
            userDetailsEntity = userSecurityService.loadUserByEmail(username);
        }
        if (userDetailsEntity == null) {
            if (BooleanUtil.isTrue(allowRegister)) {
                userDetailsEntity = userSecurityService.register(username);
            } else {
                log.debug("user:" + username + " not found.");
                throw AuthenticationExceptionUtil.throwUserNotFound(username);
            }
        }
        UserDetails userDetails = UserDetailsServiceImpl.convert(username, userDetailsEntity);

        CodeAuthenticationToken authenticationResult = new CodeAuthenticationToken(userDetails, codeCredential, userDetails.getAuthorities());

        preAuthenticationChecks.check(userDetails);
        return authenticationResult;
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return CodeAuthenticationToken.class.isAssignableFrom(authentication);
    }

}
